package com.xuecheng.content.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xuecheng.api.content.model.dto.CourseBaseDTO;
import com.xuecheng.api.content.model.dto.CourseTeacherDTO;
import com.xuecheng.api.content.model.dto.TeachplanDTO;
import com.xuecheng.api.content.model.qo.QueryCourseModel;
import com.xuecheng.api.content.model.vo.CourseAuditVO;
import com.xuecheng.api.content.model.vo.CourseBaseVO;
import com.xuecheng.api.system.model.dto.CourseCategoryDTO;
import com.xuecheng.common.domain.code.CommonErrorCode;
import com.xuecheng.common.domain.page.PageRequestParams;
import com.xuecheng.common.domain.page.PageVO;
import com.xuecheng.common.domain.response.RestResponse;
import com.xuecheng.common.enums.common.CommonEnum;
import com.xuecheng.common.enums.content.CourseAuditEnum;
import com.xuecheng.common.enums.content.CourseChargeEnum;
import com.xuecheng.common.enums.content.CourseModeEnum;
import com.xuecheng.common.enums.content.TeachPlanEnum;
import com.xuecheng.common.exception.ExceptionCast;
import com.xuecheng.common.util.JsonUtil;
import com.xuecheng.common.util.StringUtil;
import com.xuecheng.content.agent.CourseCategoryApiAgent;
import com.xuecheng.content.common.constant.ContentErrorCode;
import com.xuecheng.content.convert.CourseBaseConvert;
import com.xuecheng.content.convert.CoursePubConvert;
import com.xuecheng.content.entity.CourseBase;
import com.xuecheng.content.entity.CourseMarket;
import com.xuecheng.content.entity.CoursePub;
import com.xuecheng.content.entity.Teachplan;
import com.xuecheng.content.mapper.CourseBaseMapper;
import com.xuecheng.content.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.producer.LocalTransactionState;
import org.apache.rocketmq.client.producer.TransactionSendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeoutException;


/**
 * <p>
 * 课程基本信息 服务实现类
 * </p>
 *
 * @author itcast
 */
@Slf4j
@Service
public class CourseBaseServiceImpl extends ServiceImpl<CourseBaseMapper, CourseBase> implements CourseBaseService {

    @Autowired
    private TeachplanService teachplanService;

    @Autowired
    private CourseCategoryApiAgent courseCategoryApiAgent;

    @Autowired
    private CourseTeacherService courseTeacherService;

    @Autowired
    private CoursePubService coursePubService;
    /*
     * 业务分析：
     *   1.当前操作是否需要开启事务
     *     增删改--开启事务
     *     查--不许要开启事务
     *   2.实现功能
     *     1.分页查询
     *       当前页
     *       每页条数
     *     2.条件查询
     *        根据课程名称      --模糊查询（like）
     *        根据课程审核状态   --精确查询（equals）
     *     3.将结果进行封装
     *      使用PageVO来封装结果数据
     *         总条数
     *         当前页
     *         每页条数
     *         当前页的集合数据
     *
     *   MP 封装mybatis
     *      -对dao（mapper）封装
     *      -对service封装:将mapper集成到service中，在service不需要将mapper注入
     *        业务接口类需要实现 mp 的接口 IService
     *        业务实现类需要集成 mp 的service的父类并实现接口
     * */

    public PageVO queryCourseList(PageRequestParams params, QueryCourseModel model, Long companyId) {
        // 1.业务判断（判断的是关键数据）
        // 判断的是分页数据
        Long pageNo = params.getPageNo();
        Integer pageSize = params.getPageSize();
        if (pageNo < 1) {
            params.setPageNo(PageRequestParams.DEFAULT_PAGE_NUM);
        }
        if (pageSize < 1) {
            params.setPageSize(PageRequestParams.DEFAULT_PAGE_SIZE);
        }
        // 2.构建查询条件
        LambdaQueryWrapper<CourseBase> queryWrapper = new LambdaQueryWrapper<>();
        //根据课程名称
        //完整版
//        if (StringUtil.isNotBlank(model.getCourseName())) {
//            queryWrapper.like(CourseBase::getName, model.getCourseName());
//        }
        //精简版
        queryWrapper.like(StringUtil.isNotBlank(model.getCourseName()),
                CourseBase::getName, model.getCourseName());
        // 根据课程审核状态
        if (StringUtil.isNotBlank(model.getAuditStatus())) {
            queryWrapper.eq(CourseBase::getAuditStatus, model.getAuditStatus());
        }
        if (!ObjectUtils.isEmpty(companyId)) {
            // 添加对companyId的查询
            queryWrapper.eq(CourseBase::getCompanyId, companyId);
        }
        queryWrapper.eq(CourseBase::getStatus, CommonEnum.USING_FLAG.getCodeInt());

        // 3.构建分页对象数据   limit  startIndex,row
        Page<CourseBase> basePage = new Page<>(params.getPageNo(), params.getPageSize());

        // 4.查询数据
        Page<CourseBase> pageResult = this.page(basePage, queryWrapper);

        // 5.将结果数据进行封装==》PageVO
        List<CourseBase> records = pageResult.getRecords();
        long total = pageResult.getTotal();

        // 数据转换 pos --> dtos
        //Collections.emptyList(); == new ArrayList(0);
        List<CourseBaseDTO> dtos = Collections.emptyList();
        if (!CollectionUtils.isEmpty(records)) {
            dtos = CourseBaseConvert.INSTANCE.entitys2dtos(records);
        }

        PageVO<CourseBaseDTO> pageVO = new PageVO<>(dtos, total, params.getPageNo(), params.getPageSize());
        return pageVO;
    }

    @Autowired
    private CourseMarketService courseMarketService;

    /*
    * 1.判断关键数据
    *   课程的id值
    *   课程的必要数据（在添加课程信息中判断）
    * 2.根据课程id查询课程基础信息
    *   判断课程数据是否存在
        判断是否是同一家机构
        判断课程的审核状态
      3.修改数据
        课程的基础信息（course_base）
        课程营销表（course_market）
      4.将修改后的结果转为dto数据返回
    * */
    @Transactional
    public CourseBaseDTO createCourseBase(CourseBaseDTO courseBaseDTO) {
        // 1.判断关键数据-->业务数据
        verifyCourseMsg(courseBaseDTO);

        //保存业务数据-->课程基础信息
        //将dto转为po数据
        CourseBase courseBase = CourseBaseConvert.INSTANCE.dto2entity(courseBaseDTO);

        //给新添加的课程赋值审核状态(新添加的课程为:未提交--数据库保存使用编码)
        courseBase.setAuditStatus(CourseAuditEnum.AUDIT_UNPAST_STATUS.getCode());
        // 如果是添加操作，数据特点为id为空
        courseBase.setId(null);

        //保存数据
        boolean courseBaseResult = this.save(courseBase);
        if (!courseBaseResult) {
            ExceptionCast.cast(ContentErrorCode.E_120001);
        }
        //保存业务数据-->课程营销
        CourseMarket courseMarket = new CourseMarket();
        courseMarket.setCharge(courseBaseDTO.getCharge());
        courseMarket.setPrice(courseBaseDTO.getPrice().floatValue());
        courseMarket.setCourseId(courseBase.getId());

        // 如果是添加操作，数据特点为id为空
        courseMarket.setId(null);

        boolean courseMarketResult = courseMarketService.save(courseMarket);
        if (!courseMarketResult) {
            ExceptionCast.cast(ContentErrorCode.E_120110);
        }
        //获得结果数据
        //po-->dto
        CourseBaseDTO resultDTo = CourseBaseConvert.INSTANCE.entity2dto(courseBase);
        resultDTo.setCharge(courseMarket.getCharge());
        resultDTo.setPrice(new BigDecimal(courseMarket.getPrice().toString()));
        return resultDTo;
    }

    private void verifyCourseMsg(CourseBaseDTO courseBaseDTO) {
        // 1.判断关键数据-->业务数据
        //判断公司id
        if (ObjectUtils.isEmpty(courseBaseDTO.getCompanyId())) {
            // 运行时异常不会污染业务代码
            ExceptionCast.cast(ContentErrorCode.E_120018);
        }
        //判断课程名称
        if (StringUtil.isBlank(courseBaseDTO.getName())) {
            ExceptionCast.cast(ContentErrorCode.E_120004);
        }
        //判断课程大分类
        if (StringUtil.isBlank(courseBaseDTO.getMt())) {
            ExceptionCast.cast(ContentErrorCode.E_120002);
        }
        //判断课程小分类
        if (StringUtil.isBlank(courseBaseDTO.getSt())) {
            ExceptionCast.cast(ContentErrorCode.E_120003);
        }
        //判断课程等级
        if (StringUtil.isBlank(courseBaseDTO.getGrade())) {
            ExceptionCast.cast(ContentErrorCode.E_120007);
        }
        //判断课程教学模式
        if (StringUtil.isBlank(courseBaseDTO.getTeachmode())) {
            ExceptionCast.cast(ContentErrorCode.E_120006);
        }
    }

    /*
     * 1.判断关键数据
     *   公司的id
     *   课程基础信息的Id
     * 2.根据课程id查询课程基础信息
     *   判断课程数据是否存在
     *   判断是否是同一家机构
     * 3.将po转为dto数据并返回
     * */
    public CourseBaseDTO getCourseBaseById(Long courseBaseId, Long companyId) {
        //1.判断关键数据
        if (ObjectUtils.isEmpty(courseBaseId) || ObjectUtils.isEmpty(companyId)) {
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }

        //2.根据课程id查询课程基础信息
        CourseBase courseBase = this.getById(courseBaseId);

        verifyPO(companyId, courseBase);
        // 根据课程id查询课程营销数据
        LambdaQueryWrapper<CourseMarket> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CourseMarket::getCourseId, courseBaseId);
        CourseMarket courseMarket = courseMarketService.getOne(queryWrapper);

        if (ObjectUtils.isEmpty(courseMarket)) {
            ExceptionCast.cast(ContentErrorCode.E_120101);
        }
        //3.将po转为dto数据并返回
        CourseBaseDTO courseBaseDTO = CourseBaseConvert.INSTANCE.entity2dto(courseBase);
        courseBaseDTO.setCharge(courseMarket.getCharge());
        // 如果课程为收费课程需要赋值价格
        if (CourseChargeEnum.CHARGE_YES.getCode().equals(courseMarket.getCharge())) {
            courseBaseDTO.setPrice(new BigDecimal(courseMarket.getPrice()));
        }

        return courseBaseDTO;
    }

    private void verifyPO(Long companyId, CourseBase courseBase) {
        //判断课程数据是否存在
        if (ObjectUtils.isEmpty(courseBase)) {
            ExceptionCast.cast(ContentErrorCode.E_120013);
        }
        //判断是否是同一家机构
        if (!(ObjectUtils.nullSafeEquals(companyId, courseBase.getCompanyId()))) {
            ExceptionCast.cast(CommonErrorCode.E_100108);
        }
    }

    /*
        * 1.判断关键数据
        *   课程的id值
        *   课程的必要数据（在添加课程信息中判断）
        * 2.根据课程id查询课程基础信息
        *   判断课程数据是否存在
            判断是否是同一家机构
            判断课程的审核状态
          3.修改数据
            课程的基础信息（course_base）
            课程营销表（course_market）
          4.将修改后的结果转为dto数据返回
        * */
    @Transactional
    public CourseBaseDTO modifyCourseBaseById(CourseBaseDTO courseBaseDTO) {
        //1.判断关键数据
        //课程的必要数据（在添加课程信息中判断）
        verifyCourseMsg(courseBaseDTO);
        //课程的id值
        if (ObjectUtils.isEmpty(courseBaseDTO.getCourseBaseId())) {
            ExceptionCast.cast(ContentErrorCode.E_120009);
        }
        //2.根据课程id查询课程基础信息
        CourseBase courseBase = this.getById(courseBaseDTO.getCourseBaseId());
        //判断课程数据是否存在
        //判断是否是同一家机构
        verifyPO(courseBaseDTO.getCompanyId(), courseBase);

        if (CommonEnum.DELETE_FLAG.getCodeInt() == courseBase.getStatus()) {
            ExceptionCast.cast(ContentErrorCode.E_120019);
        }
        //判断课程的审核状态
        if (CourseAuditEnum.AUDIT_PUBLISHED_STATUS.getCode().equals(courseBase.getAuditStatus()) ||
                CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode().equals(courseBase.getAuditStatus()) ||
                CourseAuditEnum.AUDIT_PASTED_STATUS.getCode().equals(courseBase.getAuditStatus())) {
            ExceptionCast.cast(ContentErrorCode.E_120011);
        }
        //修改数据
        //课程的基础信息（course_base）
        CourseBase modifyPO = CourseBaseConvert.INSTANCE.dto2entity(courseBaseDTO);
        // 修改  po数据必须有id值
        boolean courseBaseResult = this.updateById(modifyPO);
        if (!courseBaseResult) {
            ExceptionCast.cast(ContentErrorCode.E_120020);

        }
        // 课程营销表（course_market）
        // 修改的数据为 charge：课程是否收费 、price 课程价格
        // 如果数据修改量较小：UpdateWrapper
        // update course_market set charge = ? , price = ? where course_id = ?
        LambdaUpdateWrapper<CourseMarket> updateWrapper = new LambdaUpdateWrapper<>();
        // set方法填写的是set后的字段
        updateWrapper.set(CourseMarket::getCharge, courseBaseDTO.getCharge());
        // 如果课程为收费课程，需要对price进行修改操作
        if (CourseChargeEnum.CHARGE_YES.getCode().equals(courseBaseDTO.getCharge())) {
            updateWrapper.set(CourseMarket::getPrice, courseBaseDTO.getPrice().floatValue());
        }
        //  eq方法填写的是where后的字段
        updateWrapper.eq(CourseMarket::getCourseId, courseBaseDTO.getCourseBaseId());
        //执行修改
        boolean courseMarketResult = courseMarketService.update(updateWrapper);
        if (!courseMarketResult) {
            ExceptionCast.cast(ContentErrorCode.E_120107);
        }
        // 4.将修改后的结果转为dto数据返回,重新查询一下
        CourseBase po = this.getById(courseBaseDTO.getCourseBaseId());

        CourseBaseDTO dtoResult = CourseBaseConvert.INSTANCE.entity2dto(po);

        dtoResult.setCharge(courseBaseDTO.getCharge());
        dtoResult.setPrice(courseBaseDTO.getPrice());
        return dtoResult;
    }

    /**
     * 1.判断关键数据的合法性
     * 课程的id值
     * 公司的id
     * 2.根据Id获得课程基础信息并进行相应的判断
     * 判断课程数据是否存在
     * 判断是否是同一家机构
     * 判断课程的审核状态
     * 3.删除数据
     *
     * @param courseBaseId
     * @param companyId
     */
    @Transactional
    public void removeCourseBase(Long courseBaseId, Long companyId) {

        //1.判断关键数据的合法性
        if (ObjectUtils.isEmpty(courseBaseId) || ObjectUtils.isEmpty(companyId)) {
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }
        //2.根据Id获得课程基础信息并进行相应的判断
        CourseBase courseBase = this.getById(courseBaseId);
        verifyPO(companyId, courseBase);
        //判断课程是否已被删除
        if (CommonEnum.DELETE_FLAG.getCodeInt() == courseBase.getStatus()) {
            ExceptionCast.cast(ContentErrorCode.E_120019);
        }
        //判断课程的审核状态
        if (CourseAuditEnum.AUDIT_PUBLISHED_STATUS.getCode().equals(courseBase.getAuditStatus()) ||
                CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode().equals(courseBase.getAuditStatus()) ||
                CourseAuditEnum.AUDIT_PASTED_STATUS.getCode().equals(courseBase.getAuditStatus())) {
            ExceptionCast.cast(ContentErrorCode.E_120012);
        }
        //3.删除数据
        //修改课程信息状态值
        courseBase.setStatus(CommonEnum.DELETE_FLAG.getCodeInt());
        boolean result = updateById(courseBase);
        if (!result) {
            ExceptionCast.cast(ContentErrorCode.E_120021);
        }

    }

    /**
     * 1. 判断关键数据
     * 课程基本信息id
     * 公司id
     * 2. 判断课程信息
     * 判断课程是否存在
     * 判断是否是同一机构
     * 判断课程是否删除
     * 判断课程审核状态
     * 3.修改课程审核状态
     */
    @Transactional
    public void submitCourseBase(Long courseBaseId, Long companyId) {
        //1. 判断关键数据
        if (ObjectUtils.isEmpty(courseBaseId) || ObjectUtils.isEmpty(companyId)) {
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }
        CourseBase courseBase = this.getById(courseBaseId);
        //2. 判断课程信息
        verifyPO(companyId, courseBase);
        //判断课程是否删除
        if (CommonEnum.DELETE_FLAG.getCodeInt().equals(courseBase.getStatus())) {
            ExceptionCast.cast(ContentErrorCode.E_120019);
        }
        //判断课程审核状态
        if (CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode().equals(courseBase.getAuditStatus()) ||
                CourseAuditEnum.AUDIT_PASTED_STATUS.getCode().equals(courseBase.getAuditStatus()) ||
                CourseAuditEnum.AUDIT_PUBLISHED_STATUS.getCode().equals(courseBase.getAuditStatus())
        ) {
            ExceptionCast.cast(ContentErrorCode.E_120014);
        }
        // 3.修改课程审核的状态
        // 下面的代码进行修改时，将实体类中数据进行全部替换（修改）
        // courseBase.setAuditStatus(CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode());
        // this.updateById(courseBase);

        // 由于修改的数据比较少，UpdateWrapper来修改数据
        // 需要修改change_date值，UpdateWrapper不会触发mp自动填充的功能
        // update course_base set audit_status=? , change_date = ? where course_id = ?
        LambdaUpdateWrapper<CourseBase> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(CourseBase::getAuditStatus, CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode());
        updateWrapper.set(CourseBase::getChangeDate, LocalDateTime.now());
        updateWrapper.eq(CourseBase::getId, courseBaseId);
        boolean result = this.update(updateWrapper);
        if (!result) {
            ExceptionCast.cast(ContentErrorCode.E_120017);
        }
    }

    /**
     * 1. 判断关键数据
     * 课程id
     * 审核状态
     * 2.判断课程信息
     * 判断课程信息是否存在
     * 判断课程信息是否删除
     * 判断课程信息审核状态 (已提交的课程才可以审核)
     * 3. 修改课程信息审核状态
     * 审核通过
     * 审核不通过
     */
    @Transactional
    public void approveCourse(CourseBaseDTO dto) {
        //1. 判断关键数据
        if (ObjectUtils.isEmpty(dto.getCourseBaseId()) || ObjectUtils.isEmpty(dto.getAuditStatus())) {
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }
        //2.判断课程信息
        CourseBase courseBase = this.getById(dto.getCourseBaseId());
        //判断课程信息是否存在
        if (ObjectUtils.isEmpty(courseBase)) {
            ExceptionCast.cast(ContentErrorCode.E_120013);
        }
        //判断课程信息是否删除
        if (CommonEnum.DELETE_FLAG.getCodeInt().equals(courseBase.getStatus())) {
            ExceptionCast.cast(ContentErrorCode.E_120019);
        }
        //判断课程信息审核状态
        if (!CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode().equals(courseBase.getAuditStatus())) {
            ExceptionCast.cast(ContentErrorCode.E_120015);
        }
        //3. 修改课程信息审核状态  由前端决定课程是否通过
        // 需要修改的审核内容：审核状态、审核意见、审核次数、审核时间、审核人(忽略)
        LambdaUpdateWrapper<CourseBase> updateWrapper = new LambdaUpdateWrapper<>();
        //修改审核状态
        updateWrapper.set(CourseBase::getAuditStatus, dto.getAuditStatus());
        //修改时间
        updateWrapper.set(CourseBase::getChangeDate, LocalDateTime.now());
        //修改审核时间
        updateWrapper.set(CourseBase::getAuditDate, LocalDateTime.now());
        //修改审核次数
        Integer auditNums = courseBase.getAuditNums();
        updateWrapper.set(CourseBase::getAuditNums, auditNums + 1);
        //修改审核意见
        updateWrapper.set(CourseBase::getAuditMind, dto.getAuditMind());
        updateWrapper.eq(CourseBase::getId, dto.getCourseBaseId());
        boolean result = this.update(updateWrapper);
        if (!result) {
            ExceptionCast.cast(ContentErrorCode.E_120017);
        }
    }

    /**
     * 注意事项
     * 1.主业务还是操作课程基本信息内容
     * 不要理解为操作什么样的数据库表,那个数据就为主业务
     * 2.业务方法返回的数据
     * 课程预览的数据模型数据DataMap数据
     * <p>
     * 业务分析:
     * 1.判断关键数据
     * courseBaseId
     * companyId
     * 2.判断业务数据
     * 2.1根据id获得课程基本数据并判断
     * 判断课程信息是否存在
     * 判断是否是同一家机构
     * 判断课程信息是否已经删除
     * 判断课程审核状态
     * 2.2获得课程营销数据
     * 2.3获得课程计划数据
     * 2.4获得课程教师数据
     * 2.5获得课程类型的名称(完善数据) 查询系统管理微服务获得数据
     * 2.6获得课程教学模式
     * CourseModelEnum 获得所有的枚举类型
     * 3.保存课程发布数据
     * 查询是否有课程所对应的课程发布信息
     * 3.1有数据
     * 修改课程发布信息
     * 3.2无数据
     * 添加课程发布数据
     * 4. 封装数据模型DataMap,并返回
     */
    @Transactional
    public Map<String, Object> preview(Long courseBaseId, Long companyId) {
        //获得课程发布数据
        CoursePub coursePub = getCoursePub(courseBaseId, companyId,false);

        //根据CoursePub生成数据模型 DatMap数据
        Map<String, Object> dataMap = generateDataMap(coursePub);

        return dataMap;
    }


    /*
     * 根据CoursePub生成数据模型DataMap数据
     *       根据模板页面里的关键4个key来生成对应数据
     * */
    private Map<String, Object> generateDataMap(CoursePub coursePub) {
        //1.构建数据模型
        Map<String, Object> dataMap = new HashMap();
        //1.课程发布key
        dataMap.put("coursePub", coursePub);

        //2.课程营销key
        String market = coursePub.getMarket();
        CourseMarket courseMarket = JsonUtil.jsonToObject(market, CourseMarket.class);
        dataMap.put("courseMarket", courseMarket);

        //3.课程模式key
        CourseModeEnum[] values = CourseModeEnum.values();
        dataMap.put("courseTeachModeEnums", values);

        //4.课程计划key
        String teachplan = coursePub.getTeachplan();
        TeachplanDTO teachplanDTO = JsonUtil.jsonToObject(teachplan, TeachplanDTO.class);
        dataMap.put("teachplanNode", teachplanDTO);

        //5.课程教师key
        String teachers = coursePub.getTeachers();
        List<CourseTeacherDTO> courseTeacherDTOS = JsonUtil.jsonToList(teachers, CourseTeacherDTO.class);
        dataMap.put("courseTeachers", courseTeacherDTOS);

        return dataMap;
    }

    /**
     * 获得课程发布数据
     * <p>
     * 业务分析:
     * 1.判断关键数据
     * courseBaseId
     * companyId
     * 2.判断业务数据
     * 2.1根据id获得课程基本数据并判断
     * 判断课程信息是否存在
     * 判断是否是同一家机构
     * 判断课程信息是否已经删除
     * 判断课程审核状态
     * 2.2获得课程营销数据
     * 2.3获得课程计划数据
     * 2.4获得课程教师数据
     * 2.5获得课程类型的名称(完善数据) 查询系统管理微
     * <p>
     * 3.保存课程发布数据
     * 查询是否有课程所对应的课程发布信息
     * 3.1有数据
     * 修改课程发布信息
     * 3.2无数据
     * 添加课程发布数据
     */
    private CoursePub getCoursePub(Long courseBaseId, Long companyId,Boolean isPublish) {
        //1.判断关键数据
        if (ObjectUtils.isEmpty(courseBaseId)) {
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }
        //2.1根据id获得课程基本数据并判断
        CourseBase courseBase = this.getById(courseBaseId);

        //判断课程数据是否存在
        if (ObjectUtils.isEmpty(courseBase)) {
            ExceptionCast.cast(ContentErrorCode.E_120013);
        }

        // 判断课程信息是否已经删除
        if (CommonEnum.DELETE_FLAG.getCodeInt().equals(courseBase.getStatus())) {
            ExceptionCast.cast(ContentErrorCode.E_120019);
        }
        //判断课程审核状态
        //companyId为空:运营平台
        //companyId不为空:教学机构
        if (ObjectUtils.isEmpty(companyId)) {
            //运营平台判断审核状态 (已提交)
            if (!CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode().equals(courseBase.getAuditStatus())) {
                ExceptionCast.cast(ContentErrorCode.E_120015);
            }
        } else {
            if (!isPublish) {
                //教学机构判断审核状态(未提交  审核未通过)
                if (CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode().equals(courseBase.getAuditStatus()) ||
                        CourseAuditEnum.AUDIT_PASTED_STATUS.getCode().equals(courseBase.getAuditStatus()) ||
                        CourseAuditEnum.AUDIT_PUBLISHED_STATUS.getCode().equals(courseBase.getAuditStatus())
                ) {
                    ExceptionCast.cast(ContentErrorCode.E_120015);
                }
            }

            //判断是否是同一家机构
            if (!(ObjectUtils.nullSafeEquals(companyId, courseBase.getCompanyId()))) {
                ExceptionCast.cast(CommonErrorCode.E_100108);
            }
        }
        //2.2获得课程营销数据
        LambdaQueryWrapper<CourseMarket> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CourseMarket::getCourseId, courseBaseId);
        CourseMarket courseMarket = courseMarketService.getOne(queryWrapper);

        //2.3获得课程计划数据
        TeachplanDTO teachplanDTO = teachplanService.queryTreeNodesByCourseId(courseBaseId, companyId);

        //2.4获得课程教师数据
        List<CourseTeacherDTO> courseTeacherDTOS = courseTeacherService.queryTeacherList(courseBaseId, companyId,true);

        //2.5获得课程类型的名称(完善数据) 查询系统管理微服务获得数据
        RestResponse<CourseCategoryDTO> mtResponse = courseCategoryApiAgent.getCourseCategoryById(courseBase.getMt());
        if (!mtResponse.isSuccessful()) {
            ExceptionCast.castWithCodeAndDesc(mtResponse.getCode(), mtResponse.getMsg());
        }
        CourseCategoryDTO mtDto = mtResponse.getResult();

        RestResponse<CourseCategoryDTO> stResponse = courseCategoryApiAgent.getCourseCategoryById(courseBase.getSt());
        if (!stResponse.isSuccessful()) {
            ExceptionCast.castWithCodeAndDesc(stResponse.getCode(), stResponse.getMsg());
        }
        CourseCategoryDTO stDto = stResponse.getResult();

        //3.保存课程发布数据
        CoursePub coursePub = CoursePubConvert.INSTANCE.courseBase2coursePub(courseBase);
        coursePub.setCourseId(courseBaseId);
        //课程营销最新数据
        String marketJsonStr = JsonUtil.objectTojson(courseMarket);
        coursePub.setMarket(marketJsonStr);
        // 由于前端的需求，要将课程营销数据的其他内容赋值到coursepub中
        coursePub.setPrice(courseMarket.getPrice());
        coursePub.setCharge(courseMarket.getCharge());

        //课程计划最新数据
        String teachplanJsonStr = JsonUtil.objectTojson(teachplanDTO);
        coursePub.setTeachplan(teachplanJsonStr);

        //课程教师最新数据
        String teacherJsonStr = JsonUtil.objectTojson(courseTeacherDTOS);
        coursePub.setTeachers(teacherJsonStr);

        //课程类型名称
        coursePub.setMtName(mtDto.getName());
        coursePub.setStName(stDto.getName());

        //查询是否有课程所对应的课程发布信息
        LambdaQueryWrapper<CoursePub> queryWrapper1 = new LambdaQueryWrapper<>();
        queryWrapper1.eq(CoursePub::getCourseId, courseBaseId);
        CoursePub po = coursePubService.getOne(queryWrapper1);
        if (ObjectUtils.isEmpty(po)) {
            //添加课程发布信息
            coursePub.setId(null);
            boolean save = coursePubService.save(coursePub);
            if (!save) {
                ExceptionCast.cast(ContentErrorCode.E_120206);
            }
        } else {
            //修改课程发布信息
            coursePub.setId(po.getId());
            boolean update = coursePubService.updateById(coursePub);
            if (!update) {
                ExceptionCast.cast(ContentErrorCode.E_120206);
            }
        }
        return coursePub;
    }

    @Value("${course.publish.topic}")
    private String topic_name;

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    /**
     * 1.判断关键数据
     * courseBaseId  companyId
     * 2.判断课程基本信息
     * 判断课程基本信息是否存在
     * 判断课程基本信息是否已经删除
     * 判断是否是同一家机构
     * 判断课程审核状态(审核通过的才能发布)
     * 3.发送事务消息
     * 发送关键数据courseBaseId
     */
    public void publish(Long courseBaseId, Long companyId) {

        //1.判断关键数据
        if (ObjectUtils.isEmpty(courseBaseId) || ObjectUtils.isEmpty(companyId)) {
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }
        //2.判断课程基本信息
        CourseBase courseBase = this.getById(courseBaseId);
        //判断课程基本信息是否存在
        //判断是否是同一家机构
        verifyPO(companyId,courseBase);
        //判断课程基本信息是否已经删除
        if (CommonEnum.DELETE_FLAG.getCodeInt().equals(courseBase.getStatus())) {
            ExceptionCast.cast(ContentErrorCode.E_120019);
        }
        //判断课程审核状态(审核通过的才能发布)
        if (!(CourseAuditEnum.AUDIT_PASTED_STATUS.getCode().equals(courseBase.getAuditStatus()))) {
            ExceptionCast.cast(ContentErrorCode.E_120015);
        }
        //3.发送事务消息
        //发送关键数据courseBaseId
        Message<Long> message = MessageBuilder.withPayload(courseBaseId).build();

        TransactionSendResult result = rocketMQTemplate.sendMessageInTransaction(topic_name, message, null);
        LocalTransactionState localTransactionState = result.getLocalTransactionState();

        //判断发送事务消息是否成功
        if (LocalTransactionState.COMMIT_MESSAGE != localTransactionState) {
            ExceptionCast.cast(ContentErrorCode.E_120202);
        }

    }

    /**
     *业务分析:
     * 保存课程发布信息,修改课程信息审核状态
     *
     * 1.判断课程是否已经发布(幂等性)
     * 已经发布,不做操作
     * 没有发布,进行发布
     * 2.获得课程发布最新数据并进行保存
     * 3.修改课程基本信息审核状态(已发布)
     *
     */
    @Transactional
    public void saveCoursePubAndModifyAuditStatus(Long courseBaseId) {

        //1.判断课程是否已经发布(幂等性)
        //已经发布,不做操作
        //没有发布,进行发布
        CourseBase courseBase = this.getById(courseBaseId);
        // 此处抛出的异常是用于事务消息执行后的结果用（成功：Commit，失败：Rollback）
        if (CourseAuditEnum.AUDIT_PUBLISHED_STATUS.getCode().equals(courseBase.getAuditStatus())) {
            ExceptionCast.cast(ContentErrorCode.E_120201);
        }
        //2.获得课程发布最新数据并进行保存
        Long companyId = courseBase.getCompanyId();
        getCoursePub(courseBaseId, companyId, true);
        //3.修改课程基本信息审核状态(已发布)
        LambdaUpdateWrapper<CourseBase> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(CourseBase::getAuditStatus, CourseAuditEnum.AUDIT_PUBLISHED_STATUS.getCode());
        updateWrapper.set(CourseBase::getChangeDate, LocalDateTime.now());
        updateWrapper.eq(CourseBase::getId, courseBaseId);
        boolean update = this.update(updateWrapper);
        if (!update) {
            ExceptionCast.cast(ContentErrorCode.E_120207);
        }
    }
}
